//! Describes the internal structure of a container within a function.
//!
//! This does *not* describe the types these are composed of.

use stencil_tysys::{FieldRef, ValueType};
use stencil_util::FieldName;

/// Describes the contents of a container.  Provides mapping between field names
/// and IDs.
///
/// Used to generate data for a function.
#[derive(Clone, Debug)]
pub struct ContainerData {
    /// What type of container it is.
    family: ContainerFamily,

    /// Real native field entries.  *Not* semantic fields.
    fields: Vec<FieldEntry>,
}

impl ContainerData {
    pub fn new(family: ContainerFamily, fields: Vec<FieldEntry>) -> Self {
        Self { family, fields }
    }

    pub fn family(&self) -> ContainerFamily {
        self.family
    }

    pub fn fields(&self) -> &[FieldEntry] {
        &self.fields
    }

    pub fn find_field_ref(&self, name: &FieldName) -> Option<FieldRef> {
        self.fields
            .iter()
            .enumerate()
            .find(|(_, e)| e.name() == name)
            .map(|(i, _)| FieldRef::from(i as u16))
    }

    pub fn get_field(&self, fr: FieldRef) -> Option<&FieldEntry> {
        self.fields.get(fr.inner() as usize)
    }

    pub fn find_field_by_name(&self, name: &FieldName) -> Option<&FieldEntry> {
        self.get_field(self.find_field_ref(name)?)
    }
}

/// Container field.
///
/// Eventually this probably will also describe the layouts of the fields within
/// the container, which together with the type informs which accessors can be
/// generated.
#[derive(Clone, Debug)]
pub struct FieldEntry {
    name: FieldName,
    ty: ValueType,
}

impl FieldEntry {
    pub fn new(name: FieldName, ty: ValueType) -> Self {
        Self { name, ty }
    }

    pub fn name(&self) -> &FieldName {
        &self.name
    }

    pub fn ty(&self) -> &ValueType {
        &self.ty
    }
}

/// Describes what kind of container the container is.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ContainerFamily {
    /// A generic container that's mapped directly into the target language.
    Generic,

    /// If the container is primarily just a buffer that we expose a view onto.
    BufWrapper,
}
